﻿using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
using System.IO;
using Microsoft.Win32;

namespace CFScript.PInvoke
{
    public class Platform
    {
        #region Platform Invokes
        private static class NativeMethods
        {
            [DllImport("coredll.dll")]
            private static extern int SystemParametersInfo(uint uiAction, uint uiParam, StringBuilder pvParam, uint fWiniIni);

            private const uint SPI_GETPLATFORMTYPE = 257;
            private const uint SPI_GETOEMINFO = 258;

            private static string GetSystemParameter(uint uiParam)
            {
                StringBuilder sb = new StringBuilder(128);
                if (SystemParametersInfo(uiParam, (uint)sb.Capacity, sb, 0) == 0)
                    throw new ApplicationException("Failed to get system parameter");
                return sb.ToString();
            }

            public static string GetPlatformType()
            {
                return GetSystemParameter(SPI_GETPLATFORMTYPE);
            }

            public static string GetOEMInfo()
            {
                return GetSystemParameter(SPI_GETOEMINFO);
            }

            // Returns true if the device has a cellular radio
            public static bool GetHasRadio()
            {
                return File.Exists(@"\Windows\Phone.dll");
                //return SystemState.PhoneRadioPresent;
            }

            public struct MEMORYSTATUS
            {
                public UInt32 dwLength;
                public UInt32 dwMemoryLoad;
                public UInt32 dwTotalPhys;
                public UInt32 dwAvailPhys;
                public UInt32 dwTotalPageFile;
                public UInt32 dwAvailPageFile;
                public UInt32 dwTotalVirtual;
                public UInt32 dwAvailVirtual;
            }

            [DllImport("CoreDll.dll")]
            public static extern void GlobalMemoryStatus(ref MEMORYSTATUS lpBuffer);
        }
        #endregion


        // Returns true if the application is running on a
        // desktop version of the Windows operating system
        public static bool IsDesktopWindows
        {
            get { return Environment.OSVersion.Platform != PlatformID.WinCE; }
        }

        // Returns true if the application is running on a
        // device powered by some form of WIndows CE based
        // operating system
        public static bool IsWindowsCE
        {
            get { return Environment.OSVersion.Platform == PlatformID.WinCE; }
        }

        // Returns true if the application is running on a
        // Windows Mobile Standard (i.e. Smartphone) device
        public static bool IsWindowsMobileStandard
        {
            get { return IsWindowsCE && (NativeMethods.GetPlatformType() == "SmartPhone"); }
        }

        // Returns true if the application is running on a
        // Windows Mobile Classic (i.e. Pocket PC without
        // cellphone) device.
        public static bool IsWindowsMobileClassic
        {
            get { return IsWindowsCE && !NativeMethods.GetHasRadio() && (NativeMethods.GetPlatformType() == "PocketPC"); }
        }

        // Returns true if the application is running on a
        // Windows Mobile Professional (i.e. Pocket PC with
        // cellphone) device.
        public static bool IsWindowsMobileProfessional
        {
            get { return IsWindowsCE && NativeMethods.GetHasRadio() && (NativeMethods.GetPlatformType() == "PocketPC"); }
        }

        // Returns true if the application is running
        // within the Device Emulator on a desktop machine
        public static bool IsEmulator
        {
            get { return IsWindowsCE && (NativeMethods.GetOEMInfo() == "Microsoft DeviceEmulator"); }
        }

        public static string OEM_INFO
        {
            get { return NativeMethods.GetOEMInfo(); }
        }

        public static string PLATFORM_TYPE
        {
            get { return NativeMethods.GetPlatformType(); }
        }

        public static string GetAKUVersion()
        {
            RegistryKey key = null;
            string aku;

            try
            {
                key = Registry.LocalMachine.OpenSubKey(@"SYSTEM\Versions");
                aku = (string)key.GetValue("Aku");
                if (aku.StartsWith("."))
                    aku = aku.Substring(1);
            }
            finally
            {
                if (key != null)
                    key.Close();
            }

            return aku;
        }

        public static Device GetDevice()
        {
            Device result = new Device();

            // Device

            result.OEM_INFO = NativeMethods.GetOEMInfo();

            result.emulator = Platform.IsEmulator;

            // OS name and version

            if (IsWindowsMobileStandard)
            {
                result.os.fullName = "Windows Mobile SmartPhone Edition";
                result.os.name = "Windows Mobile";
            }
            else if (IsWindowsMobileClassic)
            {
                result.os.fullName = "Windows Mobile Classic";
                result.os.name = "Windows Mobile";
            }
            else if (IsWindowsMobileProfessional)
            {
                result.os.fullName = "Windows Mobile Professional Edition";
                result.os.name = "Windows Mobile";
            }

            result.os.ce_version = Environment.OSVersion.Version.Major.ToString() + "." + Environment.OSVersion.Version.Minor.ToString();
            result.os.akuVersion = GetAKUVersion();
            result.aku = result.os.akuVersion;

            //http://en.wikipedia.org/wiki/Adaptation_kit_upgrade
            if (result.aku == "1.0" || result.aku == "1.1" || result.aku == "2.0" || result.aku == "2.1" || result.aku == "2.2" || result.aku == "2.3" ||
                result.aku == "2.5" || result.aku == "3.0" || result.aku == "3.2" || result.aku == "3.5" || result.aku == "3.5.2")
            {
                result.os.wm_version = "5.0";
            }
            else if (result.aku == "0.2" || result.aku == "0.4.4")
            {
                result.os.wm_version = "6.0";
            }
            else if (result.aku == "1.5.1" || result.aku == "1.5.2" || result.aku == "1.4.6")
            {
                result.os.wm_version = "6.1";
            }
            else if (result.aku == "5.3.11" || result.aku == "5.3.10" || result.aku == "5.0.60")
            {
                result.os.wm_version = "6.5";
            }
            // TODO: 6.5.1, 6.5.3 & 6.5.5 ??

            if (string.IsNullOrEmpty(result.os.wm_version))
            {
                if (result.os.ce_version == "5.1")
                {
                    result.os.wm_version = "5.0";
                }
                else if (result.os.ce_version == "5.2")
                {
                    if (Environment.OSVersion.Version.Build.ToString().Length == 4)
                    {
                        result.os.wm_version = "6.0";
                    }
                    else if (Environment.OSVersion.Version.Build.ToString().Length == 5)
                    {
                        result.os.wm_version = "6.1";
                    }
                }
            }

            if (string.IsNullOrEmpty(result.os.wm_version))
            {
                result.os.wm_version = "Unknown";
            }

            result.os.fullName += " v. " + result.os.wm_version;

            // Compact Framework related

            result.runningFramework = GetFrameworkFriendlyName(Environment.Version.ToString() + "0");
            List<string> installedVersions = new List<string>();

            RegistryKey key = null;

            try
            {
                key = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\.NetCompactFramework");
                string[] versions = key.GetValueNames();
                foreach (string version in versions)
                {
                    installedVersions.Add(GetFrameworkFriendlyName(version));
                }
            }
            finally
            {
                if (key != null)
                    key.Close();
            }

            if (installedVersions.Count > 0)
            {
                result.supportedFrameworks = installedVersions;
            }

            // Screen properties

            result.screen.Width = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Width;
            result.screen.Height = System.Windows.Forms.Screen.PrimaryScreen.Bounds.Height;

            if (result.screen.Width == 240 && result.screen.Height == 320)
            {
                result.screen.Resolution = Device.ScreenSize.QVGA;
            }
            else if (result.screen.Width == 480 && result.screen.Height == 640)
            {
                result.screen.Resolution = Device.ScreenSize.VGA;
            }
            else
            {
                result.screen.Resolution = Device.ScreenSize.UNKNOWN;
            }

            // Memory

            NativeMethods.MEMORYSTATUS memStatus = new NativeMethods.MEMORYSTATUS();
            NativeMethods.GlobalMemoryStatus(ref memStatus);

            result.memory = new Device.MemoryStatus();
            result.memory.Length = memStatus.dwLength;
            result.memory.MemoryLoad = memStatus.dwMemoryLoad;
            result.memory.TotalPageFile = memStatus.dwTotalPageFile;
            result.memory.TotalPhysical = memStatus.dwTotalPhys;
            result.memory.TotalVirtual = memStatus.dwTotalVirtual;
            result.memory.AvailablePageFile = memStatus.dwAvailPageFile;
            result.memory.AvailablePhysical = memStatus.dwAvailPhys;
            result.memory.AvailableVirtual = memStatus.dwAvailVirtual;

            return result;
        }

        private static string GetFrameworkFriendlyName(string version)
        {//http://blog.opennetcf.com/ncowburn/2007/08/22/HOWTODeterminingTheNETCompactFrameworkVersion.aspx
            string result = "";

            if (version == "1.0.2268.00")
            {
                result = "1.0 RTM";
            }
            else if (version == "1.0.3111.00")
            {
                result = "1.0 SP1";
            }
            else if (version == "1.0.3226.00")
            {
                result = "1.0 SP2 (Recalled)";
            }
            else if (version == "1.0.3227.00")
            {
                result = "1.0 SP2 Beta";
            }
            else if (version == "1.0.3316.00")
            {
                result = "1.0 SP2 RTM";
            }
            else if (version == "1.0.4177.00")
            {
                result = "1.0 SP3 Beta";
            }
            else if (version == "1.0.4292.00")
            {
                result = "1.0 SP3 RTM";
            }
            else if (version == "2.0.4037.00")
            {
                result = "2.0 May CPT";
            }
            else if (version == "2.0.4135.00")
            {
                result = "2.0 Beta 1";
            }
            else if (version == "2.0.4317.00")
            {
                result = "2.0 November CTP";
            }
            else if (version == "2.0.4278.00")
            {
                result = "2.0 December CTP";
            }
            else if (version == "2.0.5056.00")
            {
                result = "2.0 Beta 2";
            }
            else if (version == "2.0.5238.00")
            {
                result = "2.0 RTM";
            }
            else if (version == "2.0.6103.00")
            {
                result = "2.0 SP1 Beta";
            }
            else if (version == "2.0.6129.00")
            {
                result = "2.0 SP1 RTM";
            }
            else if (version == "2.0.7045.00")
            {
                result = "2.0 SP2 RTM";
            }
            else if (version == "3.5.7066.00")
            {
                result = "3.5 Beta 1";
            }
            else if (version == "3.5.7121.00")
            {
                result = "3.5 Beta 2";
            }
            else if (version == "3.5.7283.00")
            {
                result = "3.5 RTM";
            }
            else
            {
                result = "Unknown Friendly Name";
            }

            return result;
        }
    }
}
